# !/usr/bin/python
# -*- encoding:utf-8 -*-
"""
数据名词简称解释：
1、十六进制列表：列表元素是一个十六进制字符串的列表
"""
import math

F = lambda x, y, z: (x & y) | ((~x) & z)
G = lambda x, y, z: (x & z) | (y & (~z))
H = lambda x, y, z: x ^ y ^ z
I = lambda x, y, z: y ^ (x | (~z))
L = lambda x, n: (((x << n) | (x >> (32 - n))) | 0xffffffff)


def data_cleansing(cleansing_list: list[str]) -> list[str]:
    """
    将输入的原数据的元素为十六进制字符串的列表（后面都称为十六进制列表）清洗为每个元素大小为一个字节的十六进制列表
    :param cleansing_list: 要清洗的数据列表
    :return: 清洗后的列表
    """
    result_list = []
    for item in cleansing_list:
        if len(item) > 4 and len(item) % 2 == 0:
            item = item[2:]
            for counter in range(0, len(item), 2):
                result_list.append('0x' + item[counter: counter + 2])
        elif len(item) == 3:
            item = item[:2] + '0' + item[2:]
            result_list.append(item)
        else:
            result_list.append(item)
    return result_list


def get_mes_bit_len(bytes_list: list[str]) -> int:
    """
    计算所给的十六进制列表的元素的数据位数总和
    :param bytes_list: 要计算的十六进制列表
    :return: 列表元素的位数总和
    """
    length_list = list(map(len, bytes_list))
    mes_length = int((sum(length_list) - 2 * len(length_list)) / 2 * 8)
    return mes_length


def reverse_hex_str(hex_str: str) -> str:
    """
    反转所给的十六进制字符串
    :param hex_str: 所给十六进制字符串
    :return: 反转后的十六进制字符串
    """
    hex_str = hex_str[2:]
    result_list = []
    for counter in range(0, len(hex_str), 2):
        result_list.append(hex_str[counter: counter + 2])
    result_list.reverse()
    result_str = '0x' + "".join(result_list)
    return result_str


def get_m_list(tmp_list):
    """
    从原数据十六进制列表中截取四个元素，并将元素合并为一个位数为四个字节的十六进制字符串
    :param tmp_list: 原数据列表
    :return: 返回所有合并后的元素列表
    """
    result_list = []
    for counter in range(0, len(tmp_list), 4):
        result_list.append('0x' + ''.join([tmp_list[counter + n][2:] for n in range(4)]))
    return result_list


def mainloop(abcd: list, m: list) -> None:
    """
    MD5处理数据的主循环
    :param abcd: 初始值列表
    :param m: 分好组、并则合成一个字符串的原数据十六进制列表
    :return: None
    """
    a, b, c, d = abcd
    for counter in range(64):
        if counter < 16:
            result_a = F(*abcd[1:])
            n = counter
        elif counter < 32:
            result_a = G(*abcd[1:])
            n = (5 * counter + 1) % 16
        elif counter < 48:
            result_a = H(*abcd[1:])
            n = (3 * counter + 1) % 16
        else:
            result_a = I(*abcd[1:])
            n = (7 * counter + 1) % 16
        a, b, c, d = d, b + L(a + result_a + eval(m[n]) + T[counter], s[counter]), b, c
    # print(b)
    abcd[0], abcd[1], abcd[2], abcd[3] = a + abcd[0], b + abcd[1], c + abcd[2], d + abcd[3]


def changeHex(m):
    """
    根据处理后的摘要列表生成MD5值
    :param m: 摘要列表
    :return: MD5值
    """
    str_0 = ''
    for counter in range(4):
        str_1 = ''
        b = (m >> counter * 8) % (1 << 8) & 0xff
        for j in range(2):
            str_1 = str16[b % 16] + str_1
            b = b // 16
        str_0 += str_1
    return str_0


# 2、初始化变量
# 初始的变量
A = 0x67452301
B = 0xEFCDAB89
C = 0x98BADCFE
D = 0x10325476
s = (
    7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
    4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15,
    21)
T = tuple(((int(4294967296 * abs(math.sin(n)))) & 0xffffffff for n in range(1, 65)))
str16 = '0123456789abcdef'


def main() -> str:
    """
    程序主进程
    :return: MD5值
    """
    # 1、将数据位数填充到N+64=n*512（N是原数据的数据位数，n是正整数）
    # 读取数据
    with open('xxxxx.xxx', 'rb') as fo:
        content = fo.read()
    # content = 'abcdefghijklmnopqrstuvwxyz'
    # 获取数据的十六进制列表和对应的二进制位数
    utf8_list = list(map(hex, content))
    utf8_list = data_cleansing(utf8_list)
    message_len = get_mes_bit_len(utf8_list)
    # 获取信息的字节长度对应的十六进制列表
    message_len_0x = hex(message_len)[2:]
    message_len_0x = '0x' + message_len_0x.rjust(16, '0')
    message_len_0x = reverse_hex_str(message_len_0x)[2:]
    msg_length_0x_list = []
    for i in range(0, len(message_len_0x), 2):
        msg_length_0x_list.append('0x' + message_len_0x[i:i + 2])
    # # 添加一位1和相应位数0
    utf8_list.append('0x80')
    message_len += 8
    i = 0
    while (message_len + i * 8 + 64) % 512 != 0:
        i += 1
    # 将上面得到的结果按顺序加入数据十六进制列表中
    utf8_list.extend(['0x00'] * i)
    utf8_list.extend(msg_length_0x_list)
    # 3、处理分组数据
    abcd_list = [A, B, C, D]
    for i in range(len(utf8_list) // 64):
        m_list = get_m_list(utf8_list[i: i + 64])
        mainloop(abcd_list, m_list)
    result = '0x' + ''.join(map(changeHex, abcd_list))
    return result


if __name__ == '__main__':
    print(main())
